package com.thuan.db;

import java.util.Date;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import pojo.Competition;
import pojo.League;
import pojo.LeagueMember;
import pojo.Reward;
import pojo.UserAccount;
import com.thuan.hibernate.Repository;

public class LeagueDAO implements ILeagueDAO{

	private static SessionFactory sessionFactory;
	
	public static void setSessionFactory(SessionFactory sessionFactory) {
		LeagueDAO.sessionFactory = sessionFactory;
	}
	
	@Override
	public List<League> listLeagues() {
		Session session = sessionFactory.openSession();

		List<League> leagues = session.createQuery("from League").list();
		session.beginTransaction().commit();
		session.close();
		
		return leagues;
	}
	
	@Override
	public List<Reward> listRewards() {
		Session session = sessionFactory.openSession();

		List<Reward> rewards = session.createQuery("from Reward").list();
		session.beginTransaction().commit();
		session.close();
		
		return rewards;
	}

	@Override
	public int addLeague(String name, Date startDate, Date endDate,
			int rewardId) {
		
		if(findLeague(name) != null)
			return -1;
		
		Reward reward = this.findReward(rewardId);
		League league = new League(name, reward, startDate, endDate);
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Integer id = (Integer) session.save(league);
		
		transaction.commit();
		session.close();
		
		return id;
	}

	public Reward findReward(int rewardId) {
		Reward result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from Reward where reward_id = :rewardId");
		query.setParameter("rewardId", rewardId);
		List<Reward> rewards = query.list();
		
		if(!rewards.isEmpty())
			result = rewards.get(0);
		
		session.close();
		return result;
	}

	@Override
	public int addCompetition(int leagueId, String usernamePlayerA, String usernamePlayerB, String usernameWinner) {
		League league = this.findLeague(leagueId);
		UserAccount playerA = Repository.findUser(usernamePlayerA);
		UserAccount playerB = Repository.findUser(usernamePlayerB);
		UserAccount winner = Repository.findUser(usernameWinner);
		
		/*if(findCompetition(playerA, playerB) != null)
			return -1;*/
		
		Competition competition = new Competition(league, playerA, playerB, winner);
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Integer id = (Integer) session.save(competition);
		
		transaction.commit();
		session.close();
		
		return id;
	}

	@Override
	public List<UserAccount> getWinners(League league) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public League findLeague(String name) {
		League result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from League where name = :name");
		query.setParameter("name", name);
		List<League> leagues = query.list();
		
		if(!leagues.isEmpty())
			result = leagues.get(0);
		
		session.close();
		return result;
	}
	
	public League findLeague(int leagueId) {
		League result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from League where league_id = :leagueId");
		query.setParameter("leagueId", leagueId);
		List<League> leagues = query.list();
		
		if(!leagues.isEmpty())
			result = leagues.get(0);
		
		session.close();
		return result;
	}

	@Override
	public Competition findCompetition(UserAccount playerA, UserAccount playerB) {
		Competition result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from Competition where playerA = :playerA and playerB = :playerB");
		query.setParameter("playerA", playerA);
		query.setParameter("playerB", playerB);
		
		List<Competition> competitions = query.list();
		
		if(!competitions.isEmpty())
			result = (Competition)competitions.get(0);
		
		session.close();
		return result;
	}
	
	public LeagueMember findLeagueMember(UserAccount player, League league){
		LeagueMember result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from LeagueMember where league = :league and player = :player");
		query.setParameter("league", league);
		query.setParameter("player", player);
		
		List<LeagueMember> leaguemembers = query.list();
		
		if(!leaguemembers.isEmpty())
			result = (LeagueMember)leaguemembers.get(0);
		
		session.close();
		return result;
	}
	
	public int addLeagueMember(int leagueId, String usernamePlayerId, int leagueScore) {
		League league = this.findLeague(leagueId);
		UserAccount player = Repository.findUser(usernamePlayerId);
		
		if(this.findLeagueMember(player, league) != null)
			return -1;
		
		LeagueMember leaguemember = new LeagueMember(league, player, leagueScore);
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		session.save(leaguemember);
		//System.out.println(session.save(leaguemember).getClass().getName());
		
		transaction.commit();
		session.close();
		
		return 1;
	}
	
	public void updateLeagueScore(int leagueId, String usernamePlayerId, int leagueRoomScore){
		League league = this.findLeague(leagueId);
		UserAccount player = Repository.findUser(usernamePlayerId);
		LeagueMember result = null;
		
		result = this.findLeagueMember(player, league);
		result.setLeague(league);
		Session session = sessionFactory.openSession();
		
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			result.setLeagueScore(leagueRoomScore + result.getLeagueScore());
			session.update(result);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			throw new RuntimeException("Could not begin transaction");
		}
		finally{
		session.close();
		}
	}
	
	public int countMemberOfLeague(League league){
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("select count (*) from LeagueMember where league = :league");
		query.setParameter("league", league);
		
		int result = ((Number) query.uniqueResult()).intValue();
		
		session.close();
		return result;
	}
	
	public List<UserAccount> listPlayersOfScore(int leagueId, int leagueScore){
		Session session = sessionFactory.openSession();

		String hql = "select lm.player from LeagueMember lm where lm.league.leagueId = :leagueId and lm.leagueScore = :leagueScore";
		Query query = session.createQuery(hql);
		query.setParameter("leagueScore", leagueScore);
		query.setParameter("leagueId", leagueId);
		List<UserAccount> result = query.list();
		session.beginTransaction().commit();
		session.close();
		
		return result;
	}
	
	public void updateRewardForWinner(String username, int prize){
		UserAccount result = null;
		
		Session session = sessionFactory.openSession();
		
		Query query = session.createQuery("from UserAccount where username = :username");
		query.setParameter("username", username);
		result = (UserAccount)query.list().get(0);
		
		//session.update(result);
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			result.setScore(result.getScore() + prize);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			throw new RuntimeException("Could not begin transaction");
		}
		finally{
		session.close();
		}
	}
	
	public List<Integer> topLeagueScore(int leagueId){
		Session session = sessionFactory.openSession();

		String hql = "select distinct leagueScore from LeagueMember where league.leagueId = :leagueId and leagueScore != 0 order by leagueScore desc";
		Query query = session.createQuery(hql);
		query.setParameter("leagueId", leagueId);
        query.setMaxResults(3);
		List<Integer> result = query.list();
		session.beginTransaction().commit();
		session.close();
		
		return result;
	}
	
	public void updateLeague(int leagueId, String name, Reward reward, Date startDate, Date endDate){
		League league = this.findLeague(leagueId);
		
		if(league == null)
			return;
		
		League result = null;
		result = this.findLeague(leagueId);
		Session session = sessionFactory.openSession();
		
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			result.setName(name);
			result.setReward(reward);
			result.setStartDate(startDate);
			result.setEndDate(endDate);
			session.update(result);
			transaction.commit();
		} catch (Exception e) {
			transaction.rollback();
			throw new RuntimeException("Could not begin transaction");
		}
		finally{
		session.close();
		}
	}

	public boolean deleteLeague(int leagueId) {
		Session session = sessionFactory.openSession();
        try{
            session.getTransaction().begin();
            League league = (League) session.get(League.class, leagueId);
            session.delete(league);
            session.flush();
            session.getTransaction().commit();
            session.close();
        }
        catch(Exception e){
            if(session.getTransaction().isActive()){
                session.getTransaction().rollback();
            }
            e.printStackTrace(System.err);
            return false;
        }
        
        return true;
	}
}
